import { useEffect, useRef, useState } from 'react'
import styles from './scss/ImageUpscaleLeftContent.module.scss'
import ImageUpscaleManager from '@/lib/imageUpscale/ImageUpscaleManager'
import { showToast } from '@/utils/toast'
import { isHttpURL, sleep } from '@/utils/common'
import ImageCompare from './ImageCompare'
import { getImageName, verificationImageFile } from '@/lib/imageUpscale/common'
import { MessageBox } from '@/utils/messageBox'
import { UpscaleModel } from '@/lib/imageUpscale/types'
import { isMobile, isWeChatBrowser } from '@/utils/adaptation'
import { UpscaleModelConfig } from '@/store/imageUpscaleConfig'

/**
 * 图片信息
 */
export interface ImageInfo {
  bytes: Uint8Array
  name: string
  width: number
  height: number
  url: string
  channels: number
}

interface Props {
  onUploadImage: (info: ImageInfo) => void
  onStartUpscale: () => void
  onOpenMobileConfig: () => void
  config: UpscaleModelConfig
}

function ImageUpscaleLeftContent(props: Props) {
  const [uploadImage, setUploadImage] = useState<ImageInfo | null>(null)
  const uploadImageName = useRef('')
  const [upscaleImage, setUpscaleImage] = useState<ImageInfo | null>(null)
  const uploadImageRef = useRef<HTMLInputElement | null>(null)
  const [running, setRunning] = useState(false)
  const runningStartTime = useRef(0)
  const [forecastEndTime, setForecastEndTime] = useState(0)
  const [progress, setProgress] = useState(0)
  const [compare, setCompare] = useState(false)
  const [dropFile, setDropFile] = useState(false)
  const [predictTime, setPredictTime] = useState(0)
  const currentUpscaleModel = useRef<UpscaleModel>(null)
  const [lastUpscaleModel, setAastUpscaleModel] = useState<UpscaleModel>(null)
  function handleUploadImage(e: React.ChangeEvent<HTMLInputElement>) {
    if (!e.target.files?.length) return
    const file = e.target.files[0]
    onSetUploadImage(file)
    e.target.value = ''
  }
  function onSetUploadImage(file: File) {
    if (!verificationImageFile(file)) {
      showToast('请上传png、jpg、jpeg、webp、bmp等有效格式的图片')
      return
    }
    const url = URL.createObjectURL(file)
    const image = new Image()
    image.src = url
    image.onload = () => {
      const canvas = document.createElement('canvas')
      canvas.width = image.width
      canvas.height = image.height
      const ctx = canvas.getContext('2d')
      ctx.drawImage(image, 0, 0, image.width, image.height)
      const imageData = ctx.getImageData(0, 0, image.width, image.height)
      setUploadImage({
        bytes: new Uint8Array(imageData.data),
        name: getImageName(file.name),
        width: image.width,
        height: image.height,
        url,
        channels: 4,
      })
      setUpscaleImage(null)
      setCompare(false)
    }
    image.onerror = () => {
      showToast('图片加载失败,程序无法识别的图片格式')
    }
  }
  useEffect(() => {
    if (uploadImage) {
      props.onUploadImage(uploadImage)
      uploadImageName.current = uploadImage.name
    }
  }, [uploadImage])
  useEffect(() => {
    const uninstalls = []
    uninstalls.push(
      ImageUpscaleManager.event.on('predictResult', (data) => {
        const canvas = document.createElement('canvas')
        canvas.width = data.width
        canvas.height = data.height
        const ctx = canvas.getContext('2d')
        ctx.putImageData(
          new ImageData(data.result, data.width, data.height),
          0,
          0,
          0,
          0,
          data.width,
          data.height
        )
        canvas.toBlob((blob) => {
          const url = URL.createObjectURL(blob)
          setUpscaleImage({
            bytes: new Uint8Array(data.result),
            name: uploadImageName.current + '-upscaled',
            width: data.width,
            height: data.height,
            url,
            channels: 4,
          })
        }, 'image/png')
        setAastUpscaleModel(currentUpscaleModel.current)
        setPredictTime(data.predictTime)
      }),
      ImageUpscaleManager.event.on('runStatusChange', (isRun) => {
        setRunning(isRun)
        setProgress(0)
      }),
      ImageUpscaleManager.event.on('predictProgress', (data) => {
        const time = Date.now() - runningStartTime.current
        if (data.progress !== 0) {
          setForecastEndTime((time / data.progress) * (100 - data.progress))
        }
        setProgress(data.progress)
      })
    )
    const onPaste = (e: ClipboardEvent) => {
      if (e.clipboardData.files.length) {
        const file = e.clipboardData.files[0]
        onSetUploadImage(file)
      }
    }
    window.addEventListener('paste', onPaste)
    return () => {
      uninstalls.forEach((uninstall) => uninstall())
      window.removeEventListener('paste', onPaste)
    }
  }, [])
  useEffect(() => {
    currentUpscaleModel.current = props.config.model
  }, [props.config.model])
  useEffect(() => {
    if (upscaleImage && !compare) {
      sleep(400).then(() => {
        const dom = document.getElementById('image-upscale-left-content')
        if (dom) {
          dom.scrollBy({ behavior: 'smooth', top: dom.scrollHeight })
        }
      })
    }
  }, [upscaleImage, compare])
  useEffect(() => {
    runningStartTime.current = running ? Date.now() : 0
    if (!running) {
      setForecastEndTime(0)
    }
  }, [running])
  function onDownloadImage() {
    if (isWeChatBrowser()) {
      MessageBox.warn(
        '无法保存',
        [
          '由于微信浏览器不支持不支持下载文件',
          '因为你放大的图片保存在浏览器内存中,长按图片保存也无法实现',
          '请点击右上角打开其他浏览器',
        ].join('\n')
      )
      setCompare(false)
      return
    }
    if (!upscaleImage) {
      showToast('放大后的图片不存在')
      return
    }
    const canvas = document.createElement('canvas')
    canvas.width = upscaleImage.width
    canvas.height = upscaleImage.height
    const ctx = canvas.getContext('2d')
    ctx.putImageData(
      new ImageData(
        Uint8ClampedArray.from(upscaleImage.bytes),
        upscaleImage.width,
        upscaleImage.height
      ),
      0,
      0,
      0,
      0,
      upscaleImage.width,
      upscaleImage.height
    )
    const saveUrl = canvas.toDataURL(
      `image/${props.config.saveType}`,
      props.config.saveCompressionRatio
    )
    const link = document.createElement('a')
    link.href = saveUrl
    link.download = upscaleImage.name + `.${props.config.saveType}`
    link.click()
  }
  function continueUpscale() {
    setUploadImage(upscaleImage)
    setCompare(false)
    setUpscaleImage(null)
  }
  const showUpscaleImage = upscaleImage && !compare
  const showUploadImage = uploadImage && !compare
  const showUploadBox = !uploadImage && !upscaleImage && !compare
  const showCompare = compare && uploadImage && upscaleImage
  let imageTransition = '0.6s'
  if (upscaleImage) {
    if (upscaleImage.width * upscaleImage.height > 1300000) {
      imageTransition = 'opacity 0.6s'
    }
  } else if (uploadImage) {
    if (uploadImage.width * uploadImage.height > 1300000) {
      imageTransition = 'opacity 0.6s'
    }
  }
  return (
    <div
      className={styles['image-upscale-left-content']}
      id="image-upscale-left-content"
      style={{
        display: compare ? 'block' : undefined,
        background: dropFile ? '#347ee236' : undefined,
      }}
      onDrop={(e) => {
        e.preventDefault()
        setDropFile(false)
        if (e.dataTransfer.files.length) {
          onSetUploadImage(e.dataTransfer.files[0])
        }
      }}
      onDragOver={(e) => {
        // if (e.dataTransfer.files.length) {
        e.preventDefault()
        setDropFile(true)
        // }
      }}
      onDragLeave={(e) => {
        e.preventDefault()
        setDropFile(false)
      }}>
      <div className={styles['image-container-wapper']}>
        {showUploadBox && (
          <div
            className={styles['upload-image-container']}
            style={{
              backgroundColor: dropFile ? '#376197e6' : undefined,
            }}
            onClick={() => uploadImageRef.current?.click()}>
            <button className={styles['upload-btn']}>上传图片</button>
            <p>拖放或者粘贴一张图片</p>
            <p
              onClick={(e) => {
                e.stopPropagation()
                const url = prompt('请输入一张有效的图片链接').trim()
                if (!isHttpURL(url)) {
                  showToast('这不是有效的图片链接')
                  return
                }
                const image = new Image()
                image.crossOrigin = 'anonymous'
                image.src = url
                image.onload = () => {
                  const canvas = document.createElement('canvas')
                  canvas.width = image.width
                  canvas.height = image.height
                  const ctx = canvas.getContext('2d')
                  ctx.drawImage(image, 0, 0)
                  canvas.toBlob((blob) => {
                    onSetUploadImage(new File([blob], 'image.png'))
                  }, 'image/png')
                }
                image.onerror = () => {
                  showToast('图片加载失败，这可能不是有效的图片链接')
                }
              }}
              className={styles['p-link']}>
              填写图片链接
            </p>
          </div>
        )}
        <div
          className={styles['image-container']}
          style={{
            width: showUploadImage ? 'var(--adapt-width)' : '0px',
            opacity: showUploadImage ? 1 : 0,
            transition: imageTransition,
          }}>
          {showUploadImage && (
            <>
              <div className={styles['container-title']}>原图</div>
              <img
                src={uploadImage.url}
                alt="原图"
                draggable={false}
                className={styles['image']}
                style={{
                  imageRendering:
                    props.config.previewMode === 'pixelated'
                      ? 'pixelated'
                      : 'auto',
                }}
                onDoubleClick={() => {
                  window.open(uploadImage.url, '_blank')
                }}
              />
              <div className={styles['tips']}>
                <p>
                  宽度：{uploadImage.width}px , 高度：{uploadImage.height}px
                </p>
                <p>运行模型：{props.config.model}</p>
                <p>运行驱动：{props.config.backend.toUpperCase()}</p>
                {running && forecastEndTime !== 0 && (
                  <p>预计结束时间：{(forecastEndTime / 1000).toFixed(2)}s</p>
                )}
              </div>
              <div className={styles['tool-btns']}>
                {!running && (
                  <>
                    <button
                      onClick={() => {
                        setUploadImage(null)
                        setUpscaleImage(null)
                        // uploadImageRef.current?.click()
                      }}>
                      重新上传
                    </button>
                    <button
                      onClick={() => {
                        setUpscaleImage(null)
                        props.onStartUpscale()
                      }}>
                      {upscaleImage ? '重新放大' : '开始放大'}
                    </button>
                    {isMobile() && (
                      <button onClick={props.onOpenMobileConfig}>
                        参数调整
                      </button>
                    )}
                  </>
                )}
                {running && (
                  <button
                    onClick={() => {
                      ImageUpscaleManager.stop()
                    }}>
                    停止
                  </button>
                )}
              </div>
            </>
          )}
        </div>
        <div
          className={styles['image-compare-container']}
          style={{
            width: showCompare ? 'var(--min-adapt)' : '0px',
            transform: `scale(${showCompare ? '1' : '.3'} )`,
            opacity: showCompare ? 1 : 0,
          }}>
          {showCompare && (
            <>
              <div className={styles['container-title']}>图片对比</div>
              <div className={styles['box']}>
                <ImageCompare
                  originUrl={uploadImage.url}
                  upScaleUrl={upscaleImage.url}
                  width={upscaleImage.width}
                  height={upscaleImage.height}
                  outImageScale={upscaleImage.width / uploadImage.width}
                  previewMode={props.config.previewMode}
                  canvasScale={Math.max(
                    1,
                    200 / Math.max(uploadImage.width, uploadImage.height)
                  )}
                />
              </div>
              {/* <img src={upscaleImage.url} alt="" className="image" /> */}
              <div className={styles['tips']}>
                宽度：{upscaleImage.width}px , 高度：{upscaleImage.height}px
              </div>
              <div className={styles['tool-btns']}>
                <button onClick={() => setCompare(false)}>返回</button>
                <button onClick={continueUpscale}>继续放大</button>
                <button onClick={onDownloadImage}>保存图片</button>
              </div>
            </>
          )}
        </div>
        <div
          className={styles['image-container']}
          style={{
            width: showUpscaleImage ? 'var(--adapt-width)' : '0px',
            opacity: showUpscaleImage ? 1 : 0,
            transition: imageTransition,
          }}>
          {showUpscaleImage && (
            <>
              <div className={styles['container-title']}>放大后</div>
              <img
                src={upscaleImage.url}
                draggable={false}
                alt="放大后"
                onDoubleClick={() => {
                  window.open(upscaleImage.url, '_blank')
                }}
                style={{
                  imageRendering:
                    props.config.previewMode === 'pixelated'
                      ? 'pixelated'
                      : 'auto',
                }}
                className={styles['image']}
              />
              <div className={styles['tips']}>
                <p>
                  宽度：{upscaleImage.width}px , 高度：{upscaleImage.height}px
                </p>
                <p>模型：{lastUpscaleModel}</p>
                <p>耗时：{(predictTime / 1000).toFixed(2)}s</p>
              </div>

              <div className={styles['tool-btns']}>
                <button onClick={onDownloadImage}>保存图片</button>
                <button onClick={continueUpscale}>继续放大</button>
                <button onClick={() => setCompare(true)}>详细比较</button>
              </div>
            </>
          )}
        </div>
      </div>
      <input
        type="file"
        ref={uploadImageRef}
        style={{ display: 'none' }}
        // accept="image/*"
        onChange={handleUploadImage}
      />
      <div
        className={styles['progress']}
        style={{
          opacity: running ? 1 : 0,
        }}>
        <div
          className={styles['progress-bar']}
          style={{ width: `${progress}%` }}>
          <div className={styles['back-color']}></div>
        </div>
      </div>
    </div>
  )
}
export default ImageUpscaleLeftContent
